package com.android.common.utils.media.screen;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.ImageReader;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
import com.android.common.R;
import com.android.common.mvp.view.ActResultCallback;
import com.android.common.mvp.view.ActResultRequest;
import com.android.common.network.ResponseBean;
import com.android.common.utils.DisplayUtil;
import com.android.common.utils.FileUtil;
import java.nio.ByteBuffer;

public class CaptureScreenUtil {

    private Activity mActivity;

    private MediaProjectionManager mManager;

    private MediaProjection mMediaProjection;

    private VirtualDisplay mVirtualDisplay;

    private ImageReader mImageReader;
    /**
     * 录屏存放路径
     */
    private String mCaptureScreenPath;
    /**
     * 正在录屏
     */
    private boolean mIsScreenRecording;
    /**
     * 屏幕宽
     */
    private int mWidth;
    /**
     * 屏幕高
     */
    private int mHeight;
    /**
     * 屏幕Dpi
     */
    private int mDensityDpi = DisplayUtil.getDensityDpi();

    /**
     * 实例
     */
    private static CaptureScreenUtil mInstance;

    private RecordScreenCallBack mCallBack;

    private CaptureScreenUtil(Activity activity) {
        mActivity = activity;
        mWidth = DisplayUtil.getRealScreenSize(mActivity).x;
        mHeight =  DisplayUtil.getRealScreenSize(mActivity).y;
    }

    public static CaptureScreenUtil getInstance(Activity activity) {
        if (mInstance == null) {
            mInstance = new CaptureScreenUtil(activity);
        }
        return mInstance;
    }


    private MediaProjectionManager createProjectionManager() {
        if (null == mManager) {
            mManager = (MediaProjectionManager) mActivity.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
        }
        return mManager;
    }

    /**
     * 创建MediaProjection
     */
    private void createMediaProjection(int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_OK) {
            mMediaProjection = createProjectionManager().getMediaProjection(resultCode, data);
        }
    }

    @SuppressLint("WrongConstant")
    private void createVirtualDisplay() {
        // start capture reader
        mImageReader = ImageReader.newInstance(mWidth, mHeight, PixelFormat.RGBA_8888, 2);
        mVirtualDisplay = mMediaProjection.createVirtualDisplay("captureScreen", mWidth, mHeight,
                mDensityDpi, getVirtualDisplayFlags(), mImageReader.getSurface(), null, null);
        mImageReader.setOnImageAvailableListener(new ImageAvailableListener(), null);
    }

    private int getVirtualDisplayFlags() {
        return DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
    }

    private class ImageAvailableListener implements ImageReader.OnImageAvailableListener {
        @Override
        public void onImageAvailable(ImageReader reader) {
            Bitmap bitmap = null;
            try (Image image = mImageReader.acquireLatestImage()) {
                if (image != null) {
                    mImageReader.setOnImageAvailableListener(null,null);
                    Image.Plane[] planes = image.getPlanes();
                    ByteBuffer buffer = planes[0].getBuffer();
                    int pixelStride = planes[0].getPixelStride();
                    int rowStride = planes[0].getRowStride();
                    int rowPadding = rowStride - pixelStride * mWidth;
                    // create bitmap
                    bitmap = Bitmap.createBitmap(mWidth + rowPadding / pixelStride, mHeight, Bitmap.Config.ARGB_8888);
                    bitmap.copyPixelsFromBuffer(buffer);
                    // write bitmap to a file
                    FileUtil.saveBitmap2File(mActivity,bitmap,mCaptureScreenPath);
                }

            } catch (Exception e) {
                e.printStackTrace();
                if (mCallBack != null){
                    ResponseBean bean = new ResponseBean();
                    bean.setMessage("capture failed");
                    mCallBack.onFailed(bean,"");
                }
            } finally {
                if (bitmap != null) {
                    bitmap.recycle();
                }

            }
            if (mCallBack != null){
                mCallBack.onSucceed(mCaptureScreenPath,"");
            }
            stopCapture();
        }
    }

    private void prepareRecord() {
        createVirtualDisplay();
    }

    /**
     * 开始屏幕录制
     */
    public void captureScreen(int resultCode, Intent data, RecordScreenCallBack captureCallBack) {
        createMediaProjection(resultCode, data);
        if (!mIsScreenRecording && (null != mMediaProjection)) {
            mCallBack = captureCallBack;
            mCaptureScreenPath = FileUtil.getCaptureScreenPath(mActivity);
            Handler handler = new Handler(); // 如果这个handler是在UI线程中创建的
            handler.postDelayed(new Runnable() {  // 开启的runnable也会在这个handler所依附线程中运行，即主线程
                @Override
                public void run() {
                    // 可更新UI或做其他事情
                    // 注意这里还在当前线程，没有开启新的线程
                    // new Runnable(){}，只是把Runnable对象以Message形式post到UI线程里的Looper中执行，并没有新开线程。
                    prepareRecord();
                }
            }, 1000); // 延时1s执行run内代码

            if (mCallBack != null){
                mCallBack.onStart(mCaptureScreenPath);
            }
            mIsScreenRecording = true;
        } else {
            Toast.makeText(mActivity, mActivity.getString(R.string.screen_record_service_un_init), Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 停止屏幕录制
     */
    private void releaseVirtualDisplay() {
        if (null != mImageReader && mIsScreenRecording) {
            mImageReader.setOnImageAvailableListener(null,null);
            mImageReader.close();
            mImageReader = null;
            FileUtil.scanFile(mActivity, mCaptureScreenPath);
        }

        if (mVirtualDisplay != null) {
            mVirtualDisplay.release();
            mVirtualDisplay = null;
        }

        mIsScreenRecording = false;
    }


    private void stopCapture() {
        releaseVirtualDisplay();
        resetMediaProjection();
        mInstance = null;
    }

    private void resetMediaProjection() {
        if (null != mMediaProjection) {
            mMediaProjection.stop();
            mMediaProjection = null;
        }
    }

    public void permissionMediaProjection(ActResultCallback scanCallback) {
        Intent intent = createProjectionManager().createScreenCaptureIntent();
        ActResultRequest actResultRequest = new ActResultRequest(mActivity);
        actResultRequest.startForResult(intent, scanCallback);
    }
}
